typedef float RealNumber;
typedef std::vector<RealNumber> RealArray;

boost::mt19937 rng;
boost::uniform_real<RealNumber> distribution(-10, 10);
boost::variate_generator<boost::mt19937&, boost::uniform_real<RealNumber> >
           die(rng, distribution);

namespace cuda {

	class ErrorMessage 
		: public runtime_error
	{
	public:
		ErrorMessage(const char* p)
			: std::runtime_error(p)
		{ }
	};

	inline void CUDA_SAFE_CALL( cudaError_t code ) {
		if (cudaSuccess != code) {
			throw ErrorMessage(cudaGetErrorString(code));
		}
	}

	class MemoryBuffer 
		: boost::noncopyable
	{
	public: 
		MemoryBuffer(int nItems, int nBytePerItem) {
			CUDA_SAFE_CALL( cudaMalloc(&_p, nItems*nBytePerItem) );
		}

		~MemoryBuffer() {
			cudaFree(_p);
		}

	public:
		void* pointer() const {
			return _p;
		}

	public:
		void* _p;
	};

	typedef boost::shared_ptr<MemoryBuffer> BufferPointer;

	template<typename PODT>
		class Array
	{
	public:
		explicit Array(int n, bool zero=false) 
			: _buffer(new MemoryBuffer(n, sizeof(PODT))
		{ 
			_start = (PODT*)_buffer->pointer();
			_finish = _start+n;
			_skip = 1;

			if (zero) {
				CUDA_SAFE_CALL( cudaMemset(_buffer->pointer(), 0, sizeof(PODT)*n)) );
			}
		}

		explicit Array(const std::vector<PODT>& data, bool async=false, cudaStream_t stream=0) 
			: _buffer(new MemoryBuffer(data.size(), sizeof(PODT)))
		{
			_start = (PODT*)_buffer->pointer();
			_finish = _start+data.size();
			_skip = 1;

			if (async) {
				CUDA_SAFE_CALL( 
					cudaMemcpyAsync(
						_buffer->pointer(), &data[0], sizeof(PODT)*data.size(), 
						cudaMemcpyHostToDevice, stream
					)
				);
			}
			else {
				CUDA_SAFE_CALL( cudaMemcpy(_buffer->pointer(),
					&data[0], sizeof(PODT)*data.size(), cudaMemcpyHostToDevice) );
			}
		}

		explicit Array(Array& source, int start, int finish, int skip=1) 
			: _buffer(source._buffer)
		{
			_start = &source[start];
			_finish = &finish[finish];
			_skip = sorces.skip()*skip;
		}

	public:
		int size() const {
			return (_finish-_start)/_skip;
		}

		int skip() const {
			return _skip;
		}

	public:
		PODT& operator[](int i) {
			return _start[i*_skip];
		}
		const PODT& operator[](int i) const {
			return _start[i*_skip];
		}

	public:
		PODT* c_pointer() {
			return _start;
		}
		const PODT* c_pointer() const {
			return _start;
		}
		PODT* f_pointer() {
			return _start-1;
		}
		const PODT* f_pointer() const {
			return _start-1;
		}

	public:
		Array clone() const {
			Array result(size());
			return result;
		}
	private:
		boost::shared_ptr<MemoryBuffer> _buffer;
		PODT* _start;
		PODT* _finish;
		int _skip;
	};

	class FloatArray
		: Array<float>
	{
	public:
		Array<float>& operator+=(const Array<float>& v0); 

	};

}
